package org.barad.architecture.analyzer.archpad.event.listeners;

import java.awt.event.InputEvent;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.MouseMotionListener;

import javax.swing.JComponent;
import javax.swing.JList;
import javax.swing.TransferHandler;

/**
 * Event listener for the mouse events that are required for
 * performing a drag-and-drop operation.
 * 
 * @author svetoslavganov@gmail.com (Svetoslav R. Ganov)
 *
 */
public class ArchDragAndDropMouseListener implements MouseListener, MouseMotionListener {
	protected MouseEvent firstMouseEvent;

	//MouseListener implementation
	
	/**
	 * @see MouseListener#mouseClicked(MouseEvent)
	 */
	public void mouseClicked(MouseEvent e) {
		/*do nothing*/
	}

	/**
	 * @see MouseListener#mouseEntered(MouseEvent)
	 */
	public void mouseEntered(MouseEvent e) {
		/*do nothing*/
	}

	/**
	 * @see MouseListener#mouseExited(MouseEvent)
	 */
	public void mouseExited(MouseEvent e) {
		/*do nothing*/	
	}

	/**
	 * Detects a press of the left mouse button.
	 * 
	 * @param A {@link MouseEvent}.
	 */
	public void mousePressed(MouseEvent e) {
		int button1DownMask = InputEvent.BUTTON1_DOWN_MASK;
		if ((e.getModifiersEx() & button1DownMask) == button1DownMask) {
			firstMouseEvent = e;
			e.consume();
		}
	}

	/**
	 * Resets the listener in order to process another 
	 * drag-and-drop operation.
	 * 
	 * @param The {@link MouseEvent}.
	 */
	public void mouseReleased(MouseEvent e) {
		firstMouseEvent = null;
	}

	//MouseMotionListener
	/**
	 * Detects the beginning of a drag operation.
	 * 
	 * @param The {@link MouseEvent}.
	 */
	public void mouseDragged(MouseEvent e) {
		if (firstMouseEvent != null) {
			e.consume();
			int dx = Math.abs(e.getX() - firstMouseEvent.getX());
			int dy = Math.abs(e.getY() - firstMouseEvent.getY());
			//Arbitrarily define a 5-pixel shift as the
			//official beginning of a drag.
			if (dx > 5 || dy > 5) {
				//This is a drag, not a click.
				JComponent c = (JComponent)e.getSource();
				//Tell the transfer handler to initiate the drag.
				TransferHandler handler = c.getTransferHandler();
				exportAsDrag(handler, c, TransferHandler.COPY);
				firstMouseEvent = null;
			}
		}
	}
	
	private void exportAsDrag(TransferHandler handler, JComponent component, 
			int transferAction) {
		if (component instanceof JList) {
			JList jList = (JList)component;
			if (jList.getSelectedValue() != null) {
				handler.exportAsDrag(component, firstMouseEvent, transferAction);
			}
		} else {
		  handler.exportAsDrag(component, firstMouseEvent, transferAction);
		}
	}

    /**
     * @see MouseMotionListener#mouseMoved(MouseEvent)
     */
	public void mouseMoved(MouseEvent e) {
		/*do nothing*/
	}
}
